<?php
class PermisosController extends AppController{
	var $uses = array('Group');
	var $aco;
	var $groups;
	var $permisos = array('create' => 'A&ntilde;adir', 'read' => 'Consultar', 'update' => 'Editar', 'delete' => 'Eliminar');
	var $relacionPermisoFuncion = array('create' => 'add', 'read' => array('view', 'index'), 'update' => 'edit', 'delete' => 'delete');
	var $group_id = null;
	var $helpers=array('Access');
	
	function index($group_id = null){
		if( $group_id == 1 ){
			die("No puede cambiar los permisos del usuario administrador. Es Dios!");
		}
		
		if( $group_id == null && empty($this->data) ){
			die("Group ID missing");
		}elseif (!empty($this->data)){
			$group_id = $this->data['Group']['group_id'];
		}
		
		if(!empty($this->data)){
			$this->_savePermissions($group_id, $this->data);
			$this->redirect(array('action' => 'index', $group_id));
		}
		
		// init instance variables
		$this->aco =& $this->Acl->Aco;
		$this->group_id = $group_id;
		
		$this->set('permisos', $this->permisos);
		$this->set('controladores', $this->_getListOfControllers());
		$this->set(compact('group_id'));
	}
	
	function _getListOfControllers(){
		$controllers = Configure::listObjects('controller');
		$appIndex = array_search('App', $controllers);
		if ($appIndex !== false ) {
			unset($controllers[$appIndex]);
		}
		$pagesIndex = array_search('Pages', $controllers);
		if ($pagesIndex !== false ) {
			unset($controllers[$pagesIndex]);
		}
		
		$controllersPermissions = array();
		
		$group =& $this->Group;
		$group->id = $this->group_id;
		foreach ($controllers as $controller){
			$permissions = array();
			foreach( $this->permisos as $permiso => $label ){
				$permissions[$permiso] = $this->Acl->check($group, "controllers/$controller", $permiso);
			}
			$controllersPermissions[$controller] = $permissions;
		}

		return $controllersPermissions;
	}
	
	function _savePermissions($group_id, $data){
		if( !is_array($data) || !is_array($data['Group']) ){
			die("La peticion recibida esta corrupta");
		}
		
		$group =& $this->Group;
	    //Allow admins to everything
	    $group->id = $group_id;
		
		foreach($data['Group'] as $controlladorPermiso => $valor){
			$tokens = explode("/", $controlladorPermiso);
			if( count($tokens) != 2 ){
				continue;
			}
			if( $valor ){
				$this->Acl->allow($group, "controllers/{$tokens[0]}", $tokens[1]);
				if(isset($this->relacionPermisoFuncion[$tokens[1]])){
					if( is_array($this->relacionPermisoFuncion[$tokens[1]]) ){
						foreach ($this->relacionPermisoFuncion[$tokens[1]] as $functionName){
							$this->Acl->allow($group, "controllers/{$tokens[0]}/".$functionName);
						}
					}else {
						$this->Acl->allow($group, "controllers/{$tokens[0]}/".$this->relacionPermisoFuncion[$tokens[1]]);
					}
				}
			} else{
				$this->Acl->deny($group, "controllers/{$tokens[0]}", $tokens[1]) ;
				if(isset($this->relacionPermisoFuncion[$tokens[1]])){
					if( is_array($this->relacionPermisoFuncion[$tokens[1]]) ){
						foreach ($this->relacionPermisoFuncion[$tokens[1]] as $functionName){
							$this->Acl->deny($group, "controllers/{$tokens[0]}/".$functionName);
						}
					}else {
						$this->Acl->deny($group, "controllers/{$tokens[0]}/".$this->relacionPermisoFuncion[$tokens[1]]);
					}
				}
			}
		}
		
	}
	
	function build_acl() {
		if (!Configure::read('debug')) {
			return $this->_stop();
		}
		$log = array();

		$aco =& $this->Acl->Aco;
		$root = $aco->node('controllers');
		if (!$root) {
			$aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers'));
			$root = $aco->save();
			$root['Aco']['id'] = $aco->id;
			$log[] = 'Created Aco node for controllers';
		} else {
			$root = $root[0];
		}

		App::import('Core', 'File');
		$Controllers = Configure::listObjects('controller');
		$appIndex = array_search('App', $Controllers);
		if ($appIndex !== false ) {
			unset($Controllers[$appIndex]);
		}
		$baseMethods = get_class_methods('Controller');
		$baseMethods[] = 'build_acl';

		$Plugins = $this->_getPluginControllerNames();
		$Controllers = array_merge($Controllers, $Plugins);

		// look at each controller in app/controllers
		foreach ($Controllers as $ctrlName) {
			$methods = $this->_getClassMethods($this->_getPluginControllerPath($ctrlName));

			// Do all Plugins First
			if ($this->_isPlugin($ctrlName)){
				$pluginNode = $aco->node('controllers/'.$this->_getPluginName($ctrlName));
				if (!$pluginNode) {
					$aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginName($ctrlName)));
					$pluginNode = $aco->save();
					$pluginNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $this->_getPluginName($ctrlName) . ' Plugin';
				}
			}
			// find / make controller node
			$controllerNode = $aco->node('controllers/'.$ctrlName);
			if (!$controllerNode) {
				if ($this->_isPlugin($ctrlName)){
					$pluginNode = $aco->node('controllers/' . $this->_getPluginName($ctrlName));
					$aco->create(array('parent_id' => $pluginNode['0']['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginControllerName($ctrlName)));
					$controllerNode = $aco->save();
					$controllerNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $this->_getPluginControllerName($ctrlName) . ' ' . $this->_getPluginName($ctrlName) . ' Plugin Controller';
				} else {
					$aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName));
					$controllerNode = $aco->save();
					$controllerNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $ctrlName;
				}
			} else {
				$controllerNode = $controllerNode[0];
			}

			//clean the methods. to remove those in Controller and private actions.
			foreach ($methods as $k => $method) {
				if (strpos($method, '_', 0) === 0) {
					unset($methods[$k]);
					continue;
				}
				if (in_array($method, $baseMethods)) {
					unset($methods[$k]);
					continue;
				}
				$methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method);
				if (!$methodNode) {
					$aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
					$methodNode = $aco->save();
					$log[] = 'Created Aco node for '. $method;
				}
			}
		}
		if(count($log)>0) {
			debug($log);
		}
	}
	

	function _getClassMethods($ctrlName = null) {
		App::import('Controller', $ctrlName);
		if (strlen(strstr($ctrlName, '.')) > 0) {
			// plugin's controller
			$num = strpos($ctrlName, '.');
			$ctrlName = substr($ctrlName, $num+1);
		}
		$ctrlclass = $ctrlName . 'Controller';
		$methods = get_class_methods($ctrlclass);

		// Add scaffold defaults if scaffolds are being used
		$properties = get_class_vars($ctrlclass);
		if (array_key_exists('scaffold',$properties)) {
			if($properties['scaffold'] == 'admin') {
				$methods = array_merge($methods, array('admin_add', 'admin_edit', 'admin_index', 'admin_view', 'admin_delete'));
			} else {
				$methods = array_merge($methods, array('add', 'edit', 'index', 'view', 'delete'));
			}
		}
		return $methods;
	}

	function _isPlugin($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) > 1) {
			return true;
		} else {
			return false;
		}
	}

	function _getPluginControllerPath($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[0] . '.' . $arr[1];
		} else {
			return $arr[0];
		}
	}

	function _getPluginName($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[0];
		} else {
			return false;
		}
	}

	function _getPluginControllerName($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[1];
		} else {
			return false;
		}
	}

	/**
	 * Get the names of the plugin controllers ...
	 *
	 * This function will get an array of the plugin controller names, and
	 * also makes sure the controllers are available for us to get the
	 * method names by doing an App::import for each plugin controller.
	 *
	 * @return array of plugin names.
	 *
	 */
	function _getPluginControllerNames() {
		App::import('Core', 'File', 'Folder');
		$paths = Configure::getInstance();
		$folder =& new Folder();
		$folder->cd(APP . 'plugins');

		// Get the list of plugins
		$Plugins = $folder->read();
		$Plugins = $Plugins[0];
		$arr = array();

		// Loop through the plugins
		foreach($Plugins as $pluginName) {
			// Change directory to the plugin
			$didCD = $folder->cd(APP . 'plugins'. DS . $pluginName . DS . 'controllers');
			// Get a list of the files that have a file name that ends
			// with controller.php
			$files = $folder->findRecursive('.*_controller\.php');

			// Loop through the controllers we found in the plugins directory
			foreach($files as $fileName) {
				// Get the base file name
				$file = basename($fileName);

				// Get the controller name
				$file = Inflector::camelize(substr($file, 0, strlen($file)-strlen('_controller.php')));
				if (!preg_match('/^'. Inflector::humanize($pluginName). 'App/', $file)) {
					if (!App::import('Controller', $pluginName.'.'.$file)) {
						debug('Error importing '.$file.' for plugin '.$pluginName);
					} else {
						/// Now prepend the Plugin name ...
						// This is required to allow us to fetch the method names.
						$arr[] = Inflector::humanize($pluginName) . "/" . $file;
					}
				}
			}
		}
		return $arr;
	}
	/*
	function tales(){
		$group =& $this->Group;
	    //Allow admins to everything
	    $group->id = 1;
		$this->Acl->allow($group, "controllers");
	}
	
	function foobar($ctrlName, $method){
		$aco =& $this->Acl->Aco;
		$root = $aco->node('controllers/'.$ctrlName);
		if ($root) {
			$methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method);
			if (!$methodNode) {
				$aco->create(array('parent_id' => $root[0]['Aco']['id'], 'model' => null, 'alias' => $method));
				$methodNode = $aco->save();
				die("Cre&eacute; un nuevo aco (controllers/$ctrlName/$method) con este ID: $aco->id");
			}
		} else {
			die("No pude hacer nada... parece que el controlador no existe :( Pero al menos lo intente");
		}
	}
	*/
}